﻿using System;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;

namespace FirstFloor.P2P
{
    /// <summary>
    /// Provides access to the Live Messenger P2P stack.
    /// </summary>
    [Scriptable]
    public abstract class P2PApplication
        : Canvas
    {
        private P2PApplicationState state;
        private HtmlTimer timeoutRemoteAppLoad;
        private P2PUserList users = new P2PUserList();
        private P2PInterop interop;

        /// <summary>
        /// Initializes a new instance of the <see cref="P2PApplication"/> class.
        /// </summary>
        public P2PApplication()
        {
            this.state = P2PApplicationState.Loading;

            this.timeoutRemoteAppLoad = new HtmlTimer();
            this.timeoutRemoteAppLoad.Interval = 10000;

            this.interop = new P2PInterop(this);
            WebApplication.Current.RegisterScriptableObject("P2PInterop", this.interop);
        }

        private void timeoutRemoteAppLoad_Tick(object sender, EventArgs e)
        {
            this.timeoutRemoteAppLoad.Stop();

            SetState(P2PApplicationState.ErrorRemoteAppLoadTimeout);
        }

        internal void SetState(P2PApplicationState state)
        {
            if (state == this.state) {
                return;
            }

            if (state == P2PApplicationState.Loaded) {
                this.timeoutRemoteAppLoad.Tick += new EventHandler(timeoutRemoteAppLoad_Tick);
                this.timeoutRemoteAppLoad.Start();
            }
            else if (state == P2PApplicationState.RemoteAppLoaded) {
                this.timeoutRemoteAppLoad.Stop();

                if (this.state == P2PApplicationState.ErrorRemoteAppLoadTimeout) {
                    Close();        // too late
                    return;
                }
            }
            else if (state == P2PApplicationState.RemoteAppClosed) {
                if (this.state != P2PApplicationState.RemoteAppLoaded) {
                    return;
                }
            }
            else if (state == P2PApplicationState.Closed) {
                if (this.state != P2PApplicationState.ErrorNotHostedInLiveMessenger) {
                    this.interop.CloseApp();
                }
            }

            this.state = state;

            OnStateChanged(state);
        }

        /// <summary>
        /// Gets the application state.
        /// </summary>
        /// <value>The state.</value>
        public P2PApplicationState State
        {
            get { return this.state; }
        }

        /// <summary>
        /// Gets or sets the remote app load timeout in ms.
        /// </summary>
        /// <value>The remote app load timeout.</value>
        public int RemoteAppLoadTimeout
        {
            get { return this.timeoutRemoteAppLoad.Interval; }
            set { this.timeoutRemoteAppLoad.Interval = value; }
        }

        /// <summary>
        /// Gets the list of participating users.
        /// </summary>
        /// <value>The local user.</value>
        public P2PUserList Users
        {
            get { return this.users; }
        }

        /// <summary>
        /// Called when the connection type has changed.
        /// </summary>
        /// <param name="type">The type.</param>
        protected internal virtual void OnConnectionTypeChanged(P2PConnectionType type)
        {
        }

        /// <summary>
        /// Called when data has been received.
        /// </summary>
        /// <param name="data">The data.</param>
        protected internal virtual void OnDataReceived(string data)
        {
        }

        /// <summary>
        /// Called when an instance message has been received.
        /// </summary>
        /// <param name="im">The im.</param>
        protected internal virtual void OnIMReceived(ref string im)
        {
        }

        /// <summary>
        /// Called when a data sent error has occurred.
        /// </summary>
        /// <param name="error">The error.</param>
        protected internal virtual void OnSendDataError(P2PDataError error)
        {
        }

        /// <summary>
        /// Called when the application state has changed.
        /// </summary>
        /// <param name="state">The state.</param>
        protected internal virtual void OnStateChanged(P2PApplicationState state)
        {
        }

        /// <summary>
        /// Enters an instant message.
        /// </summary>
        /// <param name="im">The im.</param>
        protected void EnterIM(string im)
        {
            this.interop.EnterIM(im);
        }

        /// <summary>
        /// Sends data to the remote party.
        /// </summary>
        /// <param name="data">The data.</param>
        protected void SendData(string data)
        {
            this.interop.SendData(data);
        }

        /// <summary>
        /// Sends an instant message.
        /// </summary>
        /// <param name="im">The im.</param>
        protected void SendIM(string im)
        {
            this.interop.SendIM(im);
        }

        /// <summary>
        /// Sends an instant message that appears to come from the user.
        /// </summary>
        /// <param name="im">The im.</param>
        protected void SendIMAsUser(string im)
        {
            this.interop.SendIMAsUser(im);
        }

        /// <summary>
        /// Closes this application instance.
        /// </summary>
        protected void Close()
        {
            SetState(P2PApplicationState.Closed);
        }

        /// <summary>
        /// Opens the specified url.
        /// </summary>
        /// <param name="url">The URL.</param>
        protected void OpenWindow(string url)
        {
            this.interop.OpenWindow(url);
        }
    }
}
